﻿using System;
using System.Web;
using System.Web.Routing;

namespace Mindfor.Web.Routing
{
	/// <summary>
	/// Check parameter to be integer with other constraints.
	/// </summary>
	public class IntConstraint : IRouteConstraint
	{
		/// <summary>
		/// Gets or sets value whether parameter value can be null.
		/// </summary>
		public bool Nullable { get; set; }

		/// <summary>
		/// Gets or sets minimum parameter value.
		/// </summary>
		public int? MinValue { get; set; }

		/// <summary>
		/// Gets or sets maximum parameter value.
		/// </summary>
		public int? MaxValue { get; set; }

		/// <summary>
		/// initializes new int constraint instance with max and min values.
		/// </summary>
		/// <param name="nullable">Can value be null.</param>
		/// <param name="minValue">Minimum parameter value.</param>
		/// <param name="maxValue">Maximum parameter value.</param>
		public IntConstraint(bool nullable, int? minValue, int? maxValue)
		{
			Nullable = nullable;
			MinValue = minValue;
			MaxValue = maxValue;
		}

		/// <summary>
		/// initializes new int not nullable constraint instance with max and min values.
		/// </summary>
		/// <param name="minValue">Minimum parameter value.</param>
		/// <param name="maxValue">Maximum parameter value.</param>
		public IntConstraint(int? minValue, int? maxValue)
			: this(false, minValue, maxValue)
		{
		}

		/// <summary>
		/// initializes new int not nullable constraint instance with min value.
		/// </summary>
		/// <param name="minValue">Minimum parameter value.</param>
		public IntConstraint(int minValue)
			: this(false, minValue, null)
		{
		}

		/// <summary>
		/// initializes new int constraint instance.
		/// </summary>
		/// <param name="nullable">Can value be null.</param>
		public IntConstraint(bool nullable)
			: this(nullable, null, null)
		{
		}

		/// <summary>
		/// Initializes new int not nullable constraint instance.
		/// </summary>
		public IntConstraint()
			: this(false, null, null)
		{
		}

		/// <summary>
		/// Matches parameter value to constraints.
		/// </summary>
		/// <param name="httpContext">Request HttpContext.</param>
		/// <param name="route">Matching route.</param>
		/// <param name="parameterName">Matching parameter name.</param>
		/// <param name="values">Route values.</param>
		/// <param name="routeDirection">Route direction.</param>
		/// <returns>True, if validation passed. Otherwise, False.</returns>
		public bool Match(HttpContextBase httpContext, Route route, string parameterName,
			RouteValueDictionary values, RouteDirection routeDirection)
		{
			if (values[parameterName] == null)
				return Nullable;

			int i;
			return int.TryParse(values[parameterName].ToString(), out i) &&
				(!MinValue.HasValue || i >= MinValue) &&
				(!MaxValue.HasValue || i <= MaxValue);
		}

		/// <summary>
		/// Returns string representation of object.
		/// </summary>
		public override string ToString()
		{
			return String.Format("IsInt({0}, {1}-{2})",
				Nullable ? "nullable": "not null",
				MinValue.HasValue ? MinValue.ToString() : "...",
				MaxValue.HasValue ? MaxValue.ToString() : "...");
		}
	}
}